<script setup lang="ts">
import { ref } from 'vue'
import {
  NTabs,
  NTabPane,
  NScrollbar
} from 'naive-ui'
import { EditorView, basicSetup } from 'codemirror'
import { EditorState } from '@codemirror/state'
import { python } from '@codemirror/lang-python'
import { barf } from 'thememirror'
import OutputService from '@/services/output.service'

const emit = defineEmits<{
  show: []
}>()

const editorDivRef = ref()
const outputTabRef = ref<HTMLDivElement>()
const outputsDomRef = ref<InstanceType<typeof NScrollbar>>()
let editor!: EditorView
const outputService = new OutputService()
const outputs = ref<{
  type: 'debug' | 'warning' | 'error',
  msg: string,
  ts: number
}[]>([])
const script = ref('')

outputService.setio((msg, type) => {
  if (type === 'script') {
    editor?.dispatch({ changes: { from: 0, to: editor.state.doc.length, insert: msg } })
    script.value = msg
    return
  }
  if (outputs.value.length > 200) {
    outputs.value.splice(0, 1)
  }
  outputs.value.push({
    type,
    msg,
    ts: Date.now()
  })
  setTimeout(() => outputsDomRef.value?.scrollBy(0, 10000), 250)
  if (type === 'error') {
    outputTabRef.value?.click()
  }
})

async function onTabChange (tab: string) {
  if (tab === 'script') {
    while (!editorDivRef.value) {
      await new Promise(res => setTimeout(res, 50))
    }
    editor = new EditorView({
      extensions: [basicSetup, python(), barf, EditorState.tabSize.of(2)],
      parent: editorDivRef.value as HTMLDivElement,
      doc: script.value
    })
  }
  emit('show')
}
</script>
<template>
  <n-tabs type="line" size="small" :tabs-padding="12">
    <n-tab-pane name="output" tab="输出">
      <template #tab>
        <div @click="onTabChange('output')" ref="outputTabRef">输出</div>
      </template>
      <n-scrollbar class="output-content" ref="outputsDomRef">
        <pre class="output" v-for="item of outputs" :key="item.ts" :class="item.type">{{ item.msg }}</pre>
      </n-scrollbar>
    </n-tab-pane>
    <n-tab-pane name="script" tab="脚本">
      <template #tab>
        <div @click="onTabChange('script')">脚本</div>
      </template>
      <n-scrollbar>
        <div class="code-wrapper" ref="editorDivRef"></div>
      </n-scrollbar>
    </n-tab-pane>
  </n-tabs>
</template>
<style scoped lang="less">
.n-tabs {
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  --n-tab-gap: 24px !important;
}
:deep(.n-tabs-nav) {
  flex-shrink: 0;
}
:deep(.n-tab-pane) {
  flex-grow: 1;
  overflow: hidden;
  padding: 0 !important;
  box-sizing: border-box;
  user-select: text;
  .output-content .n-scrollbar-content {
    padding: 12px 0px 12px 12px !important;
  }
  .code-wrapper {
    height: 100%;
    .cm-editor {
      height: 100%;
    }
  }
}
.output {
  margin: 0;
  tab-size: 4;
  font-size: 16px;
  line-height: 18px;
  &.warning {
    color: rgb(218, 124, 0);
  }
  &.error {
    color: rgb(226, 16, 16);
  }
}
</style>
